// HodgePodge.m --

// PAK 7/31/88 -- coded on Aari ST
// PAK 4/26/92 -- ported to NeXT
// PAK 11/1/92 -- trying 4-bit Color-station format

#import "math.h"
#import <appkit/NXBitmapImageRep.h>
#import "HodgePodge.h"

@implementation HodgePodge

long random();
void wrap_cell_edges();
HodgePodge *Self;

- init
{	[super init];
	Cf = &z1;
	Ct = &z2;
	return [self Randomize :nil];
}

- Randomize :sender;
{	int i, j;
	for (i=1; i<=c_yh; i++)
		for (j=1; j<=c_xw; j++)
			(*Cf)[i][j] = random() % (n);
	wrap_cell_edges(Cf);
	return self;
}

- drawSelf:(const NXRect *)rects :(int)rectCount
{	n 					= rint([NumStates floatValue]);
	force 				= [DrivingForce floatValue]*n;
	Healthy2Sick 		= [HealthysAffectOnSick floatValue]*n/8;
	Recover2Sick 		= [RecoveringsAffectOnSick floatValue]*n/8;
	cellsHorizontally 	= [CellsHorizontally floatValue];
	cellsVertically 	= [CellsVertically floatValue];
	intiTimedEntry([MaxFramesPsecond floatValue]);
	initTable([DisplayColorPhase floatValue], [DisplayColorDir floatValue]);
	if (bitmap == 0)
	{	bitmap = [[NXBitmapImageRep alloc] 		initData:(unsigned char *)image 
				pixelsWide :c_xw				pixelsHigh :c_yh
				bitsPerSample:4					samplesPerPixel:Ncolors+1
				hasAlpha:YES					isPlanar:NO
				colorSpace:Ncolors>1? NX_RGBColorSpace:NX_OneIsWhiteColorSpace
				bytesPerRow:0					bitsPerPixel:0];
		[self setOpaque:YES];
		[self compute];
	}
	[bitmap drawIn :&bounds];
	return self;
}

/*
 *	Each cell has a Health h, an integer from 0 to N.
 *	If the cell is recovering (0 < h < N), its new health is the average of
 *		its 8 neighbors plus a Curing Force f, expressed as a fraction of N.
 *	If the cell is sick (h = 0), its new health is A * the number of healthy
 *		neighbors plus B * the number of recovering neighbors.
 *	If the cell is healthy (h = N), it becomes sick (presumably from 
 *		complacency).
 */	
- (void)compute
{	register int j;
	register cell_image *pCf;		// Pointer to Cell_image, From buffer
	register cell_image *pCt, *tmp;	// Pointer to Cell_image, To buffer
	register colorStationPixel *pS;	// Pointer to Screen_image
	register int x, y;
	register int s;
	register int a, b;
	register int sick=0, healthy=n;

	Self = self;
	if (Cf == 0)
		[self init];
	for (y=1; y<=c_yh; y++)					//iterate over Y (except edges)
	{	pCf = (cell_image *)&(*Cf)[y][1];
		pCt = (cell_image *)&(*Ct)[y][1];
		pS = (colorStationPixel *)&image[y-1][0];
		for (x=1; x<=c_xw; x++)				//iterate over X (except edges)
		{	j = (*pCf)[0][0];
			if (j <= sick)			// SICK: look at 8 neighbors
			{	a = 0;					// count of sick neighbors
				b = 0;					// count of recovering neighbors
				(j=(*pCf)[-1][-1])? (j>=healthy? a++: b++): 0;
				(j=(*pCf)[-1][ 0])? (j>=healthy? a++: b++): 0;
				(j=(*pCf)[-1][ 1])? (j>=healthy? a++: b++): 0;
				(j=(*pCf)[ 0][-1])? (j>=healthy? a++: b++): 0;
				(j=(*pCf)[ 0][ 1])? (j>=healthy? a++: b++): 0;
				(j=(*pCf)[ 1][-1])? (j>=healthy? a++: b++): 0;
				(j=(*pCf)[ 1][ 0])? (j>=healthy? a++: b++): 0;
				(j=(*pCf)[ 1][ 1])? (j>=healthy? a++: b++): 0;
				s = a * Healthy2Sick  +  b * Recover2Sick;
			}
			else if (j < healthy)	// RECOVERING: average neighbors, + force
				s=  ((*pCf)[-1][-1]+(*pCf)[-1][0]+(*pCf)[-1][1]
					+(*pCf)[0][-1]               +(*pCf)[0][1]
					+(*pCf)[1][-1] +(*pCf)[1][0] +(*pCf)[1][1])/8.0 + force;
			else					// HEALTHY: become sick again
				s = 0;

			(*pCt)[0][0] = s = s>n? n: s;

			s = s*255/n;
			pS->alpha = -1;
			pS->red   = redTable[s];
			pS->green = greenTable[s];
			pS->blue  = blueTable[s];
			pS++;

			pCf = (cell_image *)&(*pCf)[0][1];
			pCt = (cell_image *)&(*pCt)[0][1];
	}	}

	tmp = Cf; Cf = Ct; Ct = tmp;
	wrap_cell_edges(Cf);
}

// makes the area conform to a torus:
// 			row/col 0 and row/col N+1 are replicated	
void wrap_cell_edges(Cf)
register cell_image *Cf;
{	register int x, y;
	int w = Self->c_xw, h = Self->c_yh;
	for (x=1; x<=w; x++)
	{	(*Cf)[h+1][x] = (*Cf)[1][x];
		(*Cf)[0  ][x] = (*Cf)[h][x];
	}
	for (y=1; y<=h; y++)
	{	(*Cf)[y][w+1] = (*Cf)[y][1];
		(*Cf)[y][0  ] = (*Cf)[y][w];
	}
	(*Cf)[0  ][0  ] = (*Cf)[h][w];
	(*Cf)[h+1][w+1] = (*Cf)[1][1];
	(*Cf)[0  ][w+1] = (*Cf)[h][1];
	(*Cf)[h+1][0  ] = (*Cf)[1][w];
}

@end
